home *** CD-ROM | disk | FTP | other *** search
- /*
- linux/fs/dmsdos/dmsdos_dec.c
-
- DMSDOS filesystem: decompression routines
-
- ******************************************************************************
- DMSDOS (Doublespace/Drivespace compressed MSDOS filesystem) for Linux
- written 1995,1996 by Frank Gockel
-
- (C) Copyright 1995,1996 by Frank Gockel
-
- Some code of the dmsdos filesystem has been copied from the msdos filesystem
- so there are the following additional copyrights:
-
- (C) Copyright 1992,1993 by Werner Almesberger (msdos filesystem)
- (C) Copyright 1994,1995 by Jacques Gelinas (mmap code)
- (C) Copyright 1992-1995 by Linus Torvalds
-
- The DMSDOS filesystem was inspired by the THS filesystem (a simple doublespace
- DS-0-2 compressed read-only filesystem) written 1994 by Thomas Scheuermann.
-
- The DMSDOS filesystem is distributed under the Gnu General Public Licence.
- See file COPYING for details.
- ******************************************************************************
-
- */
-
- #include <linux/kernel.h>
- #include <linux/sched.h>
- #include <linux/errno.h>
- #include <linux/string.h>
- #include <linux/stat.h>
- #include <linux/mm.h>
- #include <linux/locks.h>
- #include <linux/fs.h>
- #include <linux/malloc.h>
- #include <linux/msdos_fs.h>
- #include <linux/dmsdos_fs.h>
-
- #include <asm/system.h>
- #include <asm/segment.h>
- #include <asm/bitops.h>
-
- extern Dblsb dblsb[];
-
- /* cluster caching...has to be reprogrammed (?)
- disabled due to multiple read problems
- (besides, I did not notice any speedup)
- unsigned char* ldc=NULL;
- int ldc_cvfnr;
- int ldc_cnr;
- */
-
- /* known compression methods */
- /* see header file */
-
- /* some functions are inline for speed reasons - this eats kernel memory */
-
- inline int getbit(unsigned char*clusterk,int*mask,int*count)
- { int ret;
-
- ret=(*mask)&clusterk[*count];
- (*mask)<<=1;
- if(*mask==256)
- { *mask=1;
- (*count)++;
- }
- return ret;
- }
-
- int getbits(unsigned char*clusterk,int*mask,int*count,int bits)
- { int orwert=1;
- int ret=0;
- int i;
-
- for(i=0;i<bits;++i)
- { if(getbit(clusterk,mask,count))ret|=orwert;
- orwert<<=1;
- }
- return ret;
- }
-
- int getDX(unsigned char*clusterk,int*mask,int*count)
- { if(!getbit(clusterk,mask,count)) return getbits(clusterk,mask,count,6);
- if(!getbit(clusterk,mask,count)) return getbits(clusterk,mask,count,8)+64;
- return getbits(clusterk,mask,count,12)+320;
- }
-
- int getCX(unsigned char*clusterk,int*mask,int*count)
- { if(getbit(clusterk,mask,count)) return 3;
- if(getbit(clusterk,mask,count)) return getbits(clusterk,mask,count,1)+4;
- if(getbit(clusterk,mask,count)) return getbits(clusterk,mask,count,2)+6;
- if(getbit(clusterk,mask,count)) return getbits(clusterk,mask,count,3)+10;
- if(getbit(clusterk,mask,count)) return getbits(clusterk,mask,count,4)+18;
- if(getbit(clusterk,mask,count)) return getbits(clusterk,mask,count,5)+34;
- if(getbit(clusterk,mask,count)) return getbits(clusterk,mask,count,6)+66;
- if(getbit(clusterk,mask,count)) return getbits(clusterk,mask,count,7)+130;
- if(getbit(clusterk,mask,count)) return getbits(clusterk,mask,count,8)+258;
- return -1;
- }
-
- int decrb(unsigned char*clusterk,int*mask,int*count,
- unsigned char*clusterd,int*pos,int*sek,int dx,int k)
- { int i,cx;
-
- if(dx==0)return -2;
- if(dx==0x113f)
- { /*printk("DMSDOS: decrb: 0x113f sync found.\n");*/
- (*sek)--;
- if(*sek==0)return -1;
- if(*pos%SECTOR_SIZE) return -2;
- return 0;
- }
- cx=getCX(clusterk,mask,count)+k;
- if(cx<=0)return -2;
- if(dx>*pos) return -2;
- for(i=0;i<cx;i++)clusterd[(*pos)+i]=clusterd[(*pos)+i-dx];
- (*pos)+=cx;
- return 0;
- }
-
- /* decompress a compressed cluster clusterk to clusterd */
- int decompress(unsigned char*clusterd, unsigned char*clusterk,
- Mdfat_entry*mde)
- {
- int sekcount;
- int r,count,mask,pos,dx;
-
- /*printk("DMSDOS: decompress: mdfatval=%d\n",mdfatval);*/
-
- sekcount=mde->size_hi_minus_1+1;
- count=0;
- mask=1;
- pos=0;
-
- switch(getbits(clusterk,&mask,&count,32))
- {
- case DS_0_0:
- case DS_0_1:
- case DS_0_2:
- /*printk("DMSDOS: decompressing DS-0-x\n");*/
- do
- { r=0;
- if(!getbit(clusterk,&mask,&count))
- { if(getbit(clusterk,&mask,&count))
- { clusterd[pos++]=getbits(clusterk,&mask,&count,7);
- }
- else
- { dx=getbits(clusterk,&mask,&count,6);
- r=decrb(clusterk,&mask,&count,clusterd,&pos,&sekcount,dx,-1);
- }
- }
- else
- { if(!getbit(clusterk,&mask,&count))
- { clusterd[pos++]=getbits(clusterk,&mask,&count,7)|128;
- }
- else
- { dx=(!getbit(clusterk,&mask,&count)) ?
- getbits(clusterk,&mask,&count,8)+64 :
- getbits(clusterk,&mask,&count,12)+320;
- r=decrb(clusterk,&mask,&count,clusterd,&pos,&sekcount,dx,-1);
- }
- }
- }
- while(r==0);
- if(r==-2)
- { printk("DMSDOS: error in DS-0-x compressed data.\n");
- return -2;
- }
- /*printk("DMSDOS: decompress finished.\n");*/
- return 0;
-
- case JM_0_0:
- case JM_0_1:
- /*printk("DMSDOS: decompressing JM-0-x\n");*/
- do
- { r=0;
- if(!getbit(clusterk,&mask,&count))
- { clusterd[pos++]=getbits(clusterk,&mask,&count,7);
- }
- else
- { if(!getbit(clusterk,&mask,&count))
- { dx=getDX(clusterk,&mask,&count);
- r=decrb(clusterk,&mask,&count,clusterd,&pos,&sekcount,dx,0);
- }
- else
- { clusterd[pos++]=getbits(clusterk,&mask,&count,7)|128;
- }
- }
- }
- while(r==0);
- if(r==-2)
- { printk("DMSDOS: error in JM-0-x compressed data.\n");
- return -2;
- }
- /*printk("DMSDOS: decompress finished.\n");*/
- return 0;
-
- case SQ_0_0:
- printk("DMSDOS: Sorry, SQ-0-0 compression not yet supported.\n");
- return -1;
-
- default:
- printk("DMSDOS: compression method not recognized.\n");
- return -1;
-
- } /* end switch */
-
- return 0;
- }
-
- /* read a complete file cluster and decompress it if necessary;
- currently only called by dmsdos_file_read;
- do not use to read directory clusters (for speed reasons);
- this function is unable to read cluster 0 (CVF root directory) */
- int dmsdos_read_cluster(struct super_block*sb,
- unsigned char*clusterd, int clusternr,int cvfnr)
- { Mdfat_entry mde;
- unsigned char*clusterk;
- int anz_sektoren;
- int i;
- struct buffer_head*bh;
- int membytes;
- int sektor;
- /*int fullsize;*/
-
- LOCK_READWRITE;
- /*printk("DMSDOS: read_cluster %d in CVF %d\n",clusternr,cvfnr+1);*/
-
- dbl_mdfat_value(sb,clusternr,cvfnr,NULL,&mde);
-
- if((mde.flags&2)==0)
- { /* hmm, cluster is unused (it's a lost or ghost cluster)
- and contains undefined data, but it *is* readable */
- printk("DMSDOS: lost cluster %d in CVF %d detected\n",clusternr,
- cvfnr+1);
- UNLOCK_READWRITE;
- return 0;
- }
-
- sektor=mde.sector_minus_1+1;
- anz_sektoren=mde.size_lo_minus_1+1;/* real sectors on disk */
- if(anz_sektoren>dblsb[cvfnr].s_sectperclust)
- { printk("DMSDOS: read_cluster: mdfat sektors > sectperclust, cutting\n");
- anz_sektoren=dblsb[cvfnr].s_sectperclust;
- }
-
- if(mde.flags&1)
- { /* cluster is not compressed */
- for(i=0;i<anz_sektoren;++i)
- { bh=read_dbl_sector(sb,sektor+i,cvfnr);
- if(bh==NULL){UNLOCK_READWRITE;return -EIO;}
- memcpy(&clusterd[i*SECTOR_SIZE],bh->b_data,SECTOR_SIZE);
- bh_free(sb,bh);
- }
- }
- else
- { /* cluster is compressed */
-
- membytes=SECTOR_SIZE*anz_sektoren;
-
- clusterk=(unsigned char*)MALLOC(membytes);
- if(clusterk==NULL)
- { printk("DMSDOS: no memory for decompression!\n");
- UNLOCK_READWRITE;
- return -2;
- }
-
- for(i=0;i<anz_sektoren;++i)
- { bh=read_dbl_sector(sb,sektor+i,cvfnr);
- if(bh==NULL)
- { FREE(clusterk);
- UNLOCK_READWRITE;
- return -EIO;
- }
- memcpy(&clusterk[i*SECTOR_SIZE],bh->b_data,SECTOR_SIZE);
- bh_free(sb,bh);
- }
-
- i=decompress(clusterd,clusterk,&mde);
-
- FREE(clusterk);
-
- if(i)
- { printk("DMSDOS: decompression of cluster %d in CVF %d failed.\n",
- clusternr,cvfnr+1);
- UNLOCK_READWRITE;
- return i;
- }
-
- }
-
- UNLOCK_READWRITE;
- return 0;
- }